import logging

from weed_shop.core.exceptions.order import InsufficientStock
from weed_shop.core.models.dto.product import ProductForSyncDTO
from weed_shop.core.models.enums.currency import Currency
from weed_shop.core.models.enums.order import OrderStatus
from weed_shop.infrastructure.database.models import OrderLine
from weed_shop.infrastructure.database.services import OrderService, PaymentMethodService, ProductService, UserService
from weed_shop.infrastructure.loyverse.api_client.main import LoyverseClient
from weed_shop.infrastructure.loyverse.sync_manager.sales_repo import SalesRepo


class LoyverseSyncManager:
    def __init__(
        self,
        bot_store_id: int,
        loyverse_store_id: str,
        loyverse_client: LoyverseClient,
        sales_repo: SalesRepo,
        product_service: ProductService,
        order_service: OrderService,
        user_service: UserService,
        payment_method_service: PaymentMethodService,
        logfile_path: str,
    ):
        self._bot_store_id = bot_store_id
        self._loyverse_store_id = loyverse_store_id
        self._loyverse_client = loyverse_client
        self._sales_repo = sales_repo
        self._product_service = product_service
        self._order_service = order_service
        self._user_service = user_service
        self._payment_method_service = payment_method_service
        self.logfile_path = logfile_path
        self._configure_logging()

    def _configure_logging(self):
        self.logger = logging.getLogger("sync_manager")
        self.logger.setLevel(logging.INFO)

        file_handler = logging.FileHandler(self.logfile_path)
        file_handler.setLevel(logging.INFO)

        # Console handler (stdout)
        console_handler = logging.StreamHandler()
        console_handler.setLevel(logging.INFO)

        log_formatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
        file_handler.setFormatter(log_formatter)
        console_handler.setFormatter(log_formatter)

        self.logger.addHandler(file_handler)
        self.logger.addHandler(console_handler)

    async def sync_bot_to_loyverse(self) -> str:
        """Синхронизация товаров bot -> loyverse"""

        bot_products: list[ProductForSyncDTO] = await self._product_service.get_products_for_sync()
        for bot_product in bot_products:
            if not bot_product.sku:
                self.logger.info(f"SKU is not set for product {bot_product.title}")  # TODO Логировать в файл
                continue
            bot_category = await self._product_service.get_category_by_id(bot_product.category_id)
            loyverse_category = await self._loyverse_client.get_category(bot_category.title)
            if not loyverse_category:
                loyverse_category = await self._loyverse_client.create_category(bot_category.title)
                if not loyverse_category:
                    continue

            loyverse_product = await self._loyverse_client.get_product(bot_product.sku)
            loyverse_product = await self._loyverse_client.create_or_update_product(
                bot_product, loyverse_category.id, item_id=loyverse_product.id if loyverse_product else None
            )
            if not loyverse_product:
                continue

            if bot_product.sync_stock_with_loyverse:
                # Обновляем остаток в loyverse
                product_stock = await self._product_service.get_product_available_quantity(
                    self._bot_store_id, 1, bot_product.id
                )
                await self._loyverse_client.update_product_variant_stock(
                    loyverse_product.variants[0].variant_id, product_stock
                )

        return self._get_logs()

    async def sync_loyverse_to_bot(self) -> str:
        """Синхронизация товаров loyverse -> bot"""

        for sale in await self._loyverse_client.get_sales():
            # Забираем продажи из loyverse
            self.logger.info(f"Processing sale {sale.receipt_number}")
            if self._sales_repo.is_sale_processed(sale.receipt_number):
                self.logger.info(f"Sale {sale.receipt_number} is already processed. Skipping")
                continue
            # Получаем товары в боте, у которых sku соответствует variant_id
            bot_products = [await self._product_service.get_product_by_sku(item.sku) for item in sale.line_items]
            bot_products = [product for product in bot_products if product]
            if not bot_products:
                self.logger.info(f"Can't find bot products for products in sale {sale.receipt_number}")
                continue
            order_lines = [
                OrderLine(product_id=product.id, quantity=item.quantity, final_unit_price=item.price)
                for product, item in zip(bot_products, sale.line_items)
            ]
            self.logger.info(f"Order lines from sale products: {order_lines}")
            # Получаем пользователя с ником loyverse
            user = await self._user_service.get_user_by_username("Loyverse")
            payment_method = await self._payment_method_service.get_payment_method_by_currency(Currency.thb)
            # Формируем заказ в боте
            try:
                order = await self._order_service.create_order(
                    summ=sale.total_money,
                    original_summ=sale.total_money,
                    user_id=user.id,
                    shop_id=self._bot_store_id,
                    delivery_zone_id=1,
                    payment_method_id=payment_method.id,
                    order_lines=order_lines,
                    comment=f"Order from loyverse. Receipt number: {sale.receipt_number}",
                    order_status=OrderStatus.closed,
                )
                self.logger.info(f"Created order №{order.id} from loyverse sale {sale.receipt_number}")
                # Помечаем продажу как обработанную
                self._sales_repo.add_sale(sale.receipt_number)
            except InsufficientStock as e:
                self.logger.info(
                    f"Not enough stock to create order with product №{e.product_id}. "
                    f"Requested quantity: {e.requested_amount}. "
                    f"Available in stock: {e.available_amount}"
                )
            except Exception as e:
                self.logger.info(f"Unexpected exception during order creation: {str(e)}")

        return self._get_logs()

    def _get_logs(self) -> str:
        """Возвращает логи из файла"""

        with open(self.logfile_path, "r+") as f:
            logs = f.read()
            f.seek(0)
            f.truncate()
        return logs
